module execute2(
        // from previous stage
        input           i_pipe_valid,
        input   [31:2]  i_pipe_pc,
        input   [31:0]  i_pipe_instr,
        input   [31:0]  i_pipe_gpr_rn,
        input   [31:0]  i_pipe_gpr_rm,
        input   [31:0]  i_pipe_gpr_rs,
        input   [31:0]  i_pipe_gpr_rd,
        input           i_pipe_gpr_we0,
        input   [ 3:0]  i_pipe_gpr_wa0,
        input           i_pipe_gpr_wa0_exc,
        input   [ 1:0]  i_pipe_gpr_dsel0_ex2,
        input   [ 1:0]  i_pipe_gpr_dsel0_ex3,
        input   [ 1:0]  i_pipe_gpr_dsel0_wb,
        input   [31:0]  i_pipe_gpr_d0_prev,
        input           i_pipe_gpr_we1,
        input   [ 3:0]  i_pipe_gpr_wa1,
        input           i_pipe_gpr_wa1_usr,
        input           i_pipe_gpr_dsel1,
        input   [14:0]  i_pipe_gpr_we,
        input   [31:0]  i_pipe_cpsr,
        input           i_pipe_cpsr_nzcv_we,
        input   [ 1:0]  i_pipe_cpsr_nzcv_dsel,
        input   [ 2:0]  i_pipe_cpsr_aif_we,
        input   [ 1:0]  i_pipe_cpsr_aif_dsel,
        input   [ 2:0]  i_pipe_cpsr_aif_d_imm,
        input           i_pipe_cpsr_mode_we,
        input   [ 1:0]  i_pipe_cpsr_mode_dsel,
        input   [ 4:0]  i_pipe_cpsr_mode_d_imm,
        input   [31:0]  i_pipe_spsr,
        input           i_pipe_spsr_we,
        input           i_pipe_spsr_dsel,
        input   [ 3:0]  i_pipe_alu_op,
        input           i_pipe_shifter_operand_imm,
        input           i_pipe_ls,
        input           i_pipe_ls_store,
        input   [ 2:0]  i_pipe_ls_addr_offset_sel,
        input   [ 1:0]  i_pipe_ls_addr_sel,
        input           i_pipe_ls_part,
        input           i_pipe_ls_half,
        input           i_pipe_ls_ld_sign_ext,
        input           i_pipe_ls_double,
        input   [ 4:0]  i_pipe_lsm_regcnt_tot,
        input   [ 4:0]  i_pipe_lsm_regcnt_dec,
        input   [ 3:0]  i_pipe_lsm_regcnt_inc,
        input           i_pipe_branch,
        input   [ 1:0]  i_pipe_branch_dest_sel,
        input   [31:2]  i_pipe_branch_dest_ex1,
        input           i_pipe_mul,
        input           i_pipe_mul_sign,
        input           i_pipe_mul_long,
        input           i_pipe_mul_add,
        input   [ 1:0]  i_pipe_ext_rot,
        input   [ 1:0]  i_pipe_ext_op,
        input           i_pipe_ext_sign,
        input           i_pipe_ext_add,
        input           i_pipe_coproc_sel,
        input   [ 3:0]  i_pipe_coproc_cp_num,
        input   [ 2:0]  i_pipe_coproc_op1,
        input   [ 2:0]  i_pipe_coproc_op2,
        input   [ 3:0]  i_pipe_coproc_crn,
        input   [ 3:0]  i_pipe_coproc_crm,

        // to next stage
        output          o_pipe_valid,
        output  [31:2]  o_pipe_pc,
        output  [31:0]  o_pipe_instr,
        output  [31:0]  o_pipe_cpsr,
        output  [31:0]  o_pipe_spsr,
        output          o_pipe_cpsr_nzcv_we,
        output  [ 1:0]  o_pipe_cpsr_nzcv_dsel,
        output  [ 2:0]  o_pipe_cpsr_aif_we,
        output  [ 1:0]  o_pipe_cpsr_aif_dsel,
        output  [ 2:0]  o_pipe_cpsr_aif_d_imm,
        output          o_pipe_cpsr_mode_we,
        output  [ 1:0]  o_pipe_cpsr_mode_dsel,
        output  [ 4:0]  o_pipe_cpsr_mode_d_imm,
        output          o_pipe_spsr_we,
        output          o_pipe_spsr_dsel,
        output  [14:0]  o_pipe_gpr_we,
        output          o_pipe_gpr_we0,
        output  [ 3:0]  o_pipe_gpr_wa0,
        output          o_pipe_gpr_wa0_exc,
        output  [ 1:0]  o_pipe_gpr_dsel0_ex3,
        output  [ 1:0]  o_pipe_gpr_dsel0_wb,
        output  [31:0]  o_pipe_gpr_d0_prev,
        output  [31:0]  o_pipe_gpr_d0_addr,
        output  [31:0]  o_pipe_gpr_d0_ext,
        output          o_pipe_gpr_we1,
        output  [ 3:0]  o_pipe_gpr_wa1,
        output          o_pipe_gpr_wa1_usr,
        output          o_pipe_gpr_dsel1,
        output  [31:0]  o_pipe_gpr_rn,
        output  [ 3:0]  o_pipe_alu_op,
        output  [31:0]  o_pipe_alu_b,
        output          o_pipe_shifter_carry_out,
        output          o_pipe_ls,
        output  [31:0]  o_pipe_ls_addr,
        output          o_pipe_ls_part,
        output          o_pipe_ls_half,
        output          o_pipe_ls_ld_sign_ext,
        output          o_pipe_ls_double,
        output  [31:0]  o_pipe_ls_st_dat2,
        output          o_pipe_ls_unaligned,
        output  [ 7:0]  o_pipe_ls_ld_tmp0,
        output  [ 7:0]  o_pipe_ls_ld_tmp1,
        output  [ 7:0]  o_pipe_ls_ld_tmp2,
        output  [ 7:0]  o_pipe_ls_ld_tmp3,
        output          o_pipe_wb_we,
        output  [31:0]  o_pipe_wb_dat,
        output  [ 3:0]  o_pipe_wb_sel,
        output          o_pipe_branch,
        output  [ 1:0]  o_pipe_branch_dest_sel,
        output  [31:2]  o_pipe_branch_dest_ex1,
        output          o_pipe_mul,
        output  [31:0]  o_pipe_mul_a,
        output  [31:0]  o_pipe_mul_b,
        output          o_pipe_mul_sign,
        output          o_pipe_mul_long,
        output          o_pipe_mul_add,
        output  [63:0]  o_pipe_mul_addend,
        output          o_pipe_mul_data_sent,
        output  [ 1:0]  o_pipe_ext_op,
        output          o_pipe_ext_add,
        output          o_pipe_coproc_sel,
        output  [ 3:0]  o_pipe_coproc_cp_num,
        output  [ 2:0]  o_pipe_coproc_op1,
        output  [ 2:0]  o_pipe_coproc_op2,
        output  [ 3:0]  o_pipe_coproc_crn,
        output  [ 3:0]  o_pipe_coproc_crm,
        output  [31:0]  o_pipe_coproc_din,

        // pipeline control
        output          o_valid
);

`include "enum.vh"

wire    [31:0]  dp_shifter_out;
wire            dp_shifter_carry_out;
wire    [31:0]  dp_imm_decoder_out;
wire            dp_imm_decoder_carry_out;
reg     [ 3:0]  wb_sel;
reg     [31:0]  dat;
wire    [31:0]  addr;
reg     [31:0]  gpr_d0_prev;
wire    [31:0]  gpr_d0_addr;
wire    [31:0]  gpr_d0_ext;

shifter u_shifter_dp(
        .i_op(i_pipe_instr[6:4]),
	.i_rm(i_pipe_gpr_rm),
	.i_carry(i_pipe_cpsr[29]),
        .i_shamt(i_pipe_instr[11:7]),
	.i_rs(i_pipe_gpr_rs[7:0]),
	.o_rm_shifted(dp_shifter_out),
	.o_carry(dp_shifter_carry_out)
);

dp_imm_decoder u_dp_imm_decoder(
        .in  (i_pipe_instr[11:0]),
        .out (dp_imm_decoder_out),
        .cin (i_pipe_cpsr[29]),
        .cout(dp_imm_decoder_carry_out)
);

addr_gen u_addr_gen(
        .i_rn(i_pipe_gpr_rn),
        .i_rm(i_pipe_gpr_rm),
        .i_imm12(i_pipe_instr[11:0]),
        .i_carry(i_pipe_cpsr[29]),
        .i_addr_sel(i_pipe_ls_addr_sel),
        .i_addr_offset_sel(i_pipe_ls_addr_offset_sel),
        .i_addr_offset_up(i_pipe_instr[23]),
        .i_lsm_p_flag(i_pipe_instr[24]),
        .i_lsm_regcnt_tot(i_pipe_lsm_regcnt_tot),
        .i_lsm_regcnt_dec(i_pipe_lsm_regcnt_dec),
        .i_lsm_regcnt_inc(i_pipe_lsm_regcnt_inc),
        .o_addr(addr),
        .o_gpr_d0_addr(gpr_d0_addr)
);

extender u_extender(
        .i_rm(i_pipe_gpr_rm),
        .i_rot(i_pipe_ext_rot),
        .i_op(i_pipe_ext_op),
        .i_sign(i_pipe_ext_sign),
        .o_result(gpr_d0_ext)
);

dat_gen u_dat_gen(
  .i_loaddr(addr[1:0]),
  .i_rd(i_pipe_gpr_rd),
  .o_dat(dat)
);

wb_sel_gen u_wb_sel_gen(
  .i_ls_part(i_pipe_ls_part),
  .i_ls_half(i_pipe_ls_half),
  .i_loaddr(addr[1:0]),
  .o_wb_sel(wb_sel)
);

always @* begin
        case (i_pipe_gpr_dsel0_ex2)
                GPR_DSEL0_EX2_PREV : gpr_d0_prev = i_pipe_gpr_d0_prev;
                GPR_DSEL0_EX2_MOVT : gpr_d0_prev = {i_pipe_instr[19:16], i_pipe_instr[11:0], i_pipe_gpr_rd[15:0]};
                GPR_DSEL0_EX2_CPSR : gpr_d0_prev = i_pipe_cpsr;
                GPR_DSEL0_EX2_SPSR : gpr_d0_prev = i_pipe_spsr;
                default            : gpr_d0_prev = 32'bx;
        endcase
end

assign o_pipe_valid = i_pipe_valid;
assign o_pipe_pc = i_pipe_pc;
assign o_pipe_instr = i_pipe_instr;
assign o_pipe_cpsr = i_pipe_cpsr;
assign o_pipe_spsr = i_pipe_spsr;
assign o_pipe_cpsr_nzcv_we = i_pipe_cpsr_nzcv_we;
assign o_pipe_cpsr_nzcv_dsel = i_pipe_cpsr_nzcv_dsel;
assign o_pipe_cpsr_aif_we = i_pipe_cpsr_aif_we;
assign o_pipe_cpsr_aif_dsel = i_pipe_cpsr_aif_dsel;
assign o_pipe_cpsr_aif_d_imm = i_pipe_cpsr_aif_d_imm;
assign o_pipe_cpsr_mode_we = i_pipe_cpsr_mode_we;
assign o_pipe_cpsr_mode_dsel = i_pipe_cpsr_mode_dsel;
assign o_pipe_cpsr_mode_d_imm = i_pipe_cpsr_mode_d_imm;
assign o_pipe_spsr_we = i_pipe_spsr_we;
assign o_pipe_spsr_dsel = i_pipe_spsr_dsel;
assign o_pipe_gpr_we = i_pipe_gpr_we;
assign o_pipe_gpr_we0 = i_pipe_gpr_we0;
assign o_pipe_gpr_wa0 = i_pipe_gpr_wa0;
assign o_pipe_gpr_wa0_exc = i_pipe_gpr_wa0_exc;
assign o_pipe_gpr_dsel0_ex3 = i_pipe_gpr_dsel0_ex3;
assign o_pipe_gpr_dsel0_wb  = i_pipe_gpr_dsel0_wb ;
assign o_pipe_gpr_we1 = i_pipe_gpr_we1;
assign o_pipe_gpr_wa1 = i_pipe_gpr_wa1;
assign o_pipe_gpr_wa1_usr = i_pipe_gpr_wa1_usr;
assign o_pipe_gpr_dsel1 = i_pipe_gpr_dsel1;
assign o_pipe_alu_op = i_pipe_alu_op;
assign o_pipe_gpr_rn = i_pipe_gpr_rn;
assign o_pipe_alu_b             = i_pipe_shifter_operand_imm ? dp_imm_decoder_out       : dp_shifter_out       ;
assign o_pipe_shifter_carry_out = i_pipe_shifter_operand_imm ? dp_imm_decoder_carry_out : dp_shifter_carry_out ;
assign o_pipe_ls = i_pipe_ls;
assign o_pipe_wb_we  = i_pipe_ls_store;
assign o_pipe_ls_addr = addr;
assign o_pipe_wb_dat = dat;
assign o_pipe_wb_sel = wb_sel;
assign o_pipe_gpr_d0_prev = gpr_d0_prev;
assign o_pipe_gpr_d0_addr = gpr_d0_addr;
assign o_pipe_gpr_d0_ext  = gpr_d0_ext ;
assign o_pipe_ls_part = i_pipe_ls_part;
assign o_pipe_ls_half = i_pipe_ls_half;
assign o_pipe_ls_ld_sign_ext = i_pipe_ls_ld_sign_ext;
assign o_pipe_ls_double = i_pipe_ls_double;
assign o_pipe_ls_st_dat2 = i_pipe_gpr_rs;
assign o_pipe_branch          = i_pipe_branch;
assign o_pipe_branch_dest_sel = i_pipe_branch_dest_sel;
assign o_pipe_branch_dest_ex1 = i_pipe_branch_dest_ex1;
assign o_pipe_ls_unaligned = i_pipe_ls_part ? i_pipe_ls_half & &o_pipe_ls_addr[1:0] : |o_pipe_ls_addr[1:0];
assign o_pipe_ls_ld_tmp0 = 8'b0;
assign o_pipe_ls_ld_tmp1 = 8'b0;
assign o_pipe_ls_ld_tmp2 = 8'b0;
assign o_pipe_ls_ld_tmp3 = 8'b0;
assign o_pipe_mul = i_pipe_mul;
assign o_pipe_mul_a = i_pipe_gpr_rm;
assign o_pipe_mul_b = i_pipe_gpr_rs;
assign o_pipe_mul_sign = i_pipe_mul_sign;
assign o_pipe_mul_long = i_pipe_mul_long;
assign o_pipe_mul_add = i_pipe_mul_add;
assign o_pipe_mul_addend = {i_pipe_mul_long ? i_pipe_gpr_rn : 32'b0, i_pipe_gpr_rd};
assign o_pipe_mul_data_sent = 1'b0;
assign o_pipe_ext_op = i_pipe_ext_op;
assign o_pipe_ext_add = i_pipe_ext_add;
assign o_pipe_coproc_sel = i_pipe_coproc_sel;
assign o_pipe_coproc_cp_num = i_pipe_coproc_cp_num;
assign o_pipe_coproc_op1 = i_pipe_coproc_op1;
assign o_pipe_coproc_op2 = i_pipe_coproc_op2;
assign o_pipe_coproc_crn = i_pipe_coproc_crn;
assign o_pipe_coproc_crm = i_pipe_coproc_crm;
assign o_pipe_coproc_din = 32'bx;

assign o_valid = i_pipe_valid;

endmodule
